// MemBandwidth.cpp : Defines the entry point for the console application.
//
#define _WIN32_WINNT 0x0601

#include "stdafx.h"
#include "../rdtsc.h"
#include <malloc.h>
#include <stdio.h>
#include <windows.h>
#include <omp.h>

const __int64 cpuFreq = 2; //GHz
int _tmain(int argc, _TCHAR* argv[])
{
	int size;
	int iter;
	int numThreads;

	size = 160 * 1024 *1024;
	iter = 200;
	numThreads = 8;
	// set process to high priority
	BOOL r;	
	DWORD affinity = 0;
	DWORD curProcessor = 0;
	curProcessor = GetCurrentProcessorNumber();
	affinity = 1 << curProcessor;
	//r = SetProcessAffinityMask(GetCurrentProcess(), affinity );
	r = SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);

	// for outsmarting optimization
	FILE* f;
	fopen_s(&f, "temp", "w");

	// init array 
	int* arr = (int*)_aligned_malloc(size, 64);
	memset(arr, 1, sizeof(arr));
	int arr_size = size / sizeof(arr[0]);
	int sum, sum1=0;

	// read test
	// start measurement
	unsigned __int64 freq, startTime, endTime;
    QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );
	//__int64 t1 = rdtsc();
    QueryPerformanceCounter( (LARGE_INTEGER *)&startTime );
	#pragma omp parallel for
	for(int i=0; i < iter; ++i)
	{	
		for(int j=0; j < arr_size; j+= 32)
		{
			sum = arr[j];
			sum1 = arr[j+1];
			sum = arr[j+2];
			sum1 = arr[j+3];
			sum = arr[j+4];
			sum1 = arr[j+5];
			sum = arr[j+6];
			sum1 = arr[j+7];
			sum = arr[j+8];
			sum1 = arr[j+9];
			sum = arr[j+10];
			sum1 = arr[j+11];
			sum = arr[j+12];
			sum1 = arr[j+13];
			sum = arr[j+14];
			sum1 = arr[j+15];
			sum = arr[j+16];
			sum1 = arr[j+17];
			sum = arr[j+18];
			sum1 = arr[j+19];
			sum = arr[j+20];
			sum1 = arr[j+21];
			sum = arr[j+22];
			sum1 = arr[j+23];
			sum = arr[j+24];
			sum1 = arr[j+25];
			sum = arr[j+26];
			sum1 = arr[j+27];
			sum = arr[j+28];
			sum1 = arr[j+29];
			sum = arr[j+30];
			sum1 = arr[j+31];
		}
	}
	
	//end measurement
	//__int64 t2 = rdtsc();
	QueryPerformanceCounter( (LARGE_INTEGER *)&endTime );
	__int64 bytesRead = (__int64)iter*(__int64)size;
	double sec = (endTime - startTime) / (double) freq;
	double ms = sec * 1000;
	double bandwidth2 = bytesRead / sec;
	bandwidth2 /= double(1024*1024*1024); // GB/s
	//double bandwidth1 = bytesRead * cpuFreq / (double)(t2 - t1); // GB/s

	fwrite(&sum, sizeof(int), 1, f);
	fwrite(&sum1, sizeof(int), 1, f);
	//fclose(f);
	//printf("bytes read: %10i  time= %.2f ms, bandwidth(rdtsc) = %.4f GB/s  bandwidth(pcounter)= %.4f GB/s\n", bytesRead, ms, bandwidth1, bandwidth2);
	//printf("running on cpu %i\n", curProcessor);
	printf("bytes read: %10I64d  time= %.2f ms, bandwidth= %.4f GB/s\n", bytesRead, ms, bandwidth2);
	//printf("bytes read: %10i  cycles: %10I64d\n", iter*size, t2 - t1);
	_aligned_free(arr);

	// write test
	int* arr2 = (int*)_aligned_malloc(size, 64);
	memset(arr2, 1, sizeof(arr2));
	int arr2_size = size / sizeof(arr2[0]);
	// start measurement
	//__int64 t1 = rdtsc();
    QueryPerformanceCounter( (LARGE_INTEGER *)&startTime );
	#pragma omp parallel for
	for(int i=0; i < iter; ++i)
	{
		for(int j=0; j < arr2_size; j+= 8)
		{
			arr2[j] = sum;
			arr2[j+1] = sum;
			arr2[j+2] = sum;
			arr2[j+3] = sum;
			arr2[j+4] = sum;
			arr2[j+5] = sum;
			arr2[j+6] = sum;
			arr2[j+7] = sum;
		}
	}
	//end measurement
	//__int64 t2 = rdtsc();
	QueryPerformanceCounter( (LARGE_INTEGER *)&endTime );
	__int64 bytesWritten = (__int64)iter*(__int64)size;
	sec = (endTime - startTime) / (double) freq;
	ms = sec * 1000;
	bandwidth2 = bytesWritten / sec;
	bandwidth2 /= double(1024*1024*1024); // GB/s
	//double bandwidth1 = bytesRead * cpuFreq / (double)(t2 - t1); // GB/s

	fwrite(&sum, sizeof(int), 1, f);
	fclose(f);
	//printf("bytes read: %10i  time= %.2f ms, bandwidth(rdtsc) = %.4f GB/s  bandwidth(pcounter)= %.4f GB/s\n", bytesRead, ms, bandwidth1, bandwidth2);
	printf("bytes written: %10I64d  time= %.2f ms, bandwidth= %.4f GB/s\n", bytesWritten, ms, bandwidth2);
	//printf("bytes read: %10i  cycles: %10I64d\n", iter*size, t2 - t1);
	_aligned_free(arr2);
	//getchar();
	return 0;
}

